home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.006 / xemacs-1 / lib / xemacs-19.13 / lisp / hyperbole / hypb.el < prev    next >
Encoding:
Text File  |  1995-08-11  |  17.7 KB  |  492 lines

  1. ;;!emacs
  2. ;;
  3. ;; FILE:         hypb.el
  4. ;; SUMMARY:      Miscellaneous Hyperbole support features.
  5. ;; USAGE:        GNU Emacs Lisp Library
  6. ;; KEYWORDS:     extensions, hypermedia
  7. ;;
  8. ;; AUTHOR:       Bob Weiner
  9. ;; ORG:          Brown U.
  10. ;;
  11. ;; ORIG-DATE:     6-Oct-91 at 03:42:38
  12. ;; LAST-MOD:      5-Aug-95 at 03:24:48 by Bob Weiner
  13. ;;
  14. ;; This file is part of Hyperbole.
  15. ;; Available for use and distribution under the same terms as GNU Emacs.
  16. ;;
  17. ;; Copyright (C) 1991-1995, Free Software Foundation, Inc.
  18. ;; Developed with support from Motorola Inc.
  19. ;;
  20. ;; DESCRIPTION:  
  21. ;; DESCRIP-END.
  22.  
  23. ;;; ************************************************************************
  24. ;;; Other required Elisp libraries
  25. ;;; ************************************************************************
  26.  
  27. (mapcar 'require '(hversion hact))
  28.  
  29. ;;; ************************************************************************
  30. ;;; Public variables
  31. ;;; ************************************************************************
  32.  
  33. (defconst hypb:help-buf-suffix " Hypb Help*"
  34.   "Suffix attached to all native Hyperbole help buffer names.")
  35.  
  36. ;;; ************************************************************************
  37. ;;; Public functions
  38. ;;; ************************************************************************
  39.  
  40. (defun hypb:call-process-p (program infile &optional predicate &rest args)
  41.   "Calls an external PROGRAM with INFILE for input.
  42. If PREDICATE is given, it is evaluated in a buffer with the PROGRAM's
  43. output and the result returned.  If PREDICATE is nil, returns t iff
  44. program has no output or just a 0-valued output.
  45. Rest of ARGS are passed as arguments to PROGRAM."
  46.   (let ((buf (get-buffer-create "*test-output*"))
  47.     (found))
  48.     (save-excursion
  49.       (set-buffer buf) (setq buffer-read-only nil) (erase-buffer)
  50.       (apply 'call-process program infile buf nil args)
  51.       (setq found 
  52.         (if predicate
  53.         (eval predicate)
  54.           (or (= (point-max) 1) ;; No output, consider cmd a success.
  55.           (and (< (point-max) 4)
  56.                (string= (buffer-substring 1 2) "0")))))
  57.       (set-buffer-modified-p nil)
  58.       (kill-buffer buf))
  59.     found))
  60.  
  61.  
  62. (defun hypb:chmod (op octal-permissions file)
  63.   "Uses OP and OCTAL-PERMISSIONS integer to set FILE permissions.
  64. OP may be +, -, xor, or default =."
  65.   (let ((func (cond ((eq op '+)   (function logior))
  66.             ((eq op '-)   (function
  67.                    (lambda (p1 p2) (logand (lognot p1) p2))))
  68.             ((eq op 'xor) (function logxor))
  69.             (t            (function (lambda (p1 p2) p1))))))
  70.     (set-file-modes file (funcall func (hypb:oct-to-int octal-permissions)
  71.                   (file-modes file)))))
  72.  
  73. (defun hypb:cmd-key-string (cmd-sym &optional keymap)
  74.   "Returns a single pretty printed key sequence string bound to CMD-SYM.
  75. Global keymap is used unless optional KEYMAP is given."
  76.   (if (and cmd-sym (symbolp cmd-sym) (fboundp cmd-sym))
  77.   (let* ((get-keys (function
  78.             (lambda (cmd-sym keymap)
  79.               (key-description (where-is-internal
  80.                     cmd-sym keymap 'first)))))
  81.      (keys (funcall get-keys cmd-sym keymap)))
  82.     (concat "{"
  83.         (if (string= keys "")
  84.         (concat (funcall get-keys 'execute-extended-command nil)
  85.             " " (symbol-name cmd-sym) " RTN")
  86.           keys)
  87.         "}"))
  88.   (error "(hypb:cmd-key-string): Invalid cmd-sym arg: %s." cmd-sym)))
  89.  
  90. (if (fboundp 'copy-tree)
  91.     (fset 'hypb:copy-sublists 'copy-tree)
  92.   ;;
  93.   ;; This function is derived from a copylefted function.
  94.   ;; Define hypb:copy-sublists if not a builtin.  This version 
  95.   ;; is a Lisp translation of the C version in Lemacs 19.8.
  96.   ;; Copyright (C) 1985, 1986, 1987, 1992, 1993 Free Software Foundation, Inc.
  97.   ;; Available for use and distribution under the GPL.
  98.   ;;
  99.   (defun hypb:copy-sublists (obj &optional vector-p)
  100.     "Return a copy of a list and substructures.
  101. The argument is copied, and any lists contained within it are copied
  102. recursively.  Circularities and shared substructures are not preserved.
  103. Second arg VECP causes vectors to be copied, too.  Strings are not copied."
  104.     (cond ((consp obj)
  105.        (let (rest)
  106.          (setq obj (copy-sequence obj)
  107.            rest obj)
  108.          (while (consp rest)
  109.            (let ((elt (car rest)))
  110.          (if quit-flag (top-level))
  111.          (if (or (consp elt) (vectorp elt))
  112.              (setcar rest (hypb:copy-sublists elt vector-p)))
  113.          (if (vectorp (cdr rest))
  114.              (setcdr rest (hypb:copy-sublists (cdr rest) vector-p)))
  115.          (setq rest (cdr rest))))))
  116.       ((and (vectorp obj) obj)
  117.        (let ((i (length obj))
  118.          (j 0)
  119.          elt)
  120.          (setq obj (copy-sequence obj))
  121.          (while (< j i)
  122.            (setq elt (aref obj j))
  123.            (if quit-flag (top-level))
  124.            (if (or (consp elt) (vectorp elt))
  125.            (aset obj j (hypb:copy-sublists elt vector-p)))
  126.            (setq j (1+ j))))))
  127.     obj))
  128.  
  129. (defun hypb:debug ()
  130.   "Loads Hyperbole hbut.el source file and sets debugging traceback flag."
  131.   (interactive)
  132.   (or (featurep 'hinit) (load "hsite"))
  133.   (or (and (featurep 'hbut)
  134.        (let ((func (hypb:indirect-function 'ebut:create)))
  135.          (not (or (hypb:v19-byte-code-p func)
  136.               (eq 'byte-code
  137.               (car (car (nthcdr 3 (hypb:indirect-function
  138.                            'ebut:create)))))))))
  139.       (load "hbut.el"))
  140.   (setq debug-on-error t))
  141.  
  142. (defun hypb:domain-name ()
  143.   "Returns current Internet domain name with '@' prepended or nil if none."
  144.   (let* ((dname-cmd (or (file-exists-p "/usr/bin/domainname")
  145.             (file-exists-p "/bin/domainname")))
  146.      (dname (or (getenv "DOMAINNAME")
  147.             (if dname-cmd
  148.             (hypb:call-process-p
  149.              "domainname" nil 
  150.              '(substring (buffer-string) 0 -1))))))
  151.     (if (or (and dname (string-match "\\." dname))
  152.         (let* ((src "/etc/resolv.conf")
  153.            (src-buf-exists-p (get-file-buffer src)))
  154.           (and (file-exists-p src) (file-readable-p src)
  155.            (save-excursion
  156.              (set-buffer (find-file-noselect src))
  157.              (goto-char (point-min))
  158.              (if (re-search-forward  "^domain[ \t]+\\([^ \t\n]+\\)"
  159.                          nil t)
  160.              (setq dname (buffer-substring (match-beginning 1)
  161.                                (match-end 1))))
  162.              (or src-buf-exists-p (kill-buffer nil))
  163.              dname))))
  164.     (concat "@" dname))))
  165.  
  166. (defun hypb:error (&rest args)
  167.   "Signals an error typically to be caught by 'hui:menu'."
  168.   (let ((msg (apply 'format args)))
  169.     (put 'error 'error-message msg)
  170.     (error msg)))
  171.  
  172. (defun hypb:functionp (obj)
  173. "Returns t if OBJ is a function, nil otherwise."
  174.   (cond
  175.     ((symbolp obj) (fboundp obj))
  176.     ((subrp obj))
  177.     ((hypb:v19-byte-code-p obj))
  178.     ((consp obj)
  179.      (if (eq (car obj) 'lambda) (listp (car (cdr obj)))))
  180.     (t nil)))
  181.  
  182. (defun hypb:function-copy (func-symbol)
  183.   "Copies FUNC-SYMBOL's body for overloading.  Returns copy of body."
  184.   (if (fboundp func-symbol)
  185.       (let ((func (hypb:indirect-function func-symbol)))
  186.     (cond ((listp func) (copy-sequence func))
  187.           ((subrp func) (error "(hypb:function-copy): `%s' is a primitive; can't copy body."
  188.                    func-symbol))
  189.           ((and (hypb:v19-byte-code-p func) (fboundp 'make-byte-code))
  190.            (let ((new-code (append func nil))) ; turn it into a list
  191.          (apply 'make-byte-code new-code)))
  192.           (t (error "(hypb:function-copy): Can't copy function body: %s" func))
  193.           ))
  194.     (error "(hypb:function-copy): `%s' symbol is not bound to a function."
  195.        func-symbol)))
  196.  
  197. (defun hypb:function-overload (func-sym prepend &rest new-forms)
  198.   "Redefine function named FUNC-SYM by either PREPENDing (or appending if nil) rest of quoted NEW-FORMS."
  199.   (let ((old-func-sym (intern
  200.             (concat "*hypb-old-"
  201.                 (symbol-name func-sym)
  202.                 "*"))))
  203.     (or (fboundp old-func-sym)
  204.     (fset old-func-sym (hypb:function-copy func-sym)))
  205.     (let* ((old-func (hypb:indirect-function old-func-sym))
  206.        (old-param-list (action:params old-func))
  207.        (param-list (action:param-list old-func))
  208.        (old-func-call
  209.          (list (if (memq '&rest old-param-list)
  210.                ;; Have to account for extra list wrapper from &rest.
  211.                (cons 'apply
  212.                  (cons (list 'quote old-func-sym) param-list))
  213.              (cons old-func-sym param-list)))))
  214.       (eval (append
  215.           (list 'defun func-sym old-param-list)
  216.           (delq nil
  217.             (list
  218.               (documentation old-func-sym)
  219.               (action:commandp old-func-sym)))
  220.           (if prepend
  221.           (append new-forms old-func-call)
  222.         (append old-func-call new-forms)))))))
  223.  
  224. (defun hypb:function-symbol-replace (func-sym sym-to-replace replace-with-sym)
  225.   "Replaces in body of FUNC-SYM SYM-TO-REPLACE with REPLACE-WITH-SYM.
  226. All occurrences within lists are replaced.  Returns body of modified FUNC-SYM."
  227.   (let ((body (hypb:indirect-function func-sym))
  228.     (arg-vector) (arg))
  229.     (if (listp body)
  230.     ;; assume V18 byte compiler
  231.     (setq arg-vector
  232.           (car (delq nil (mapcar
  233.                    (function
  234.                  (lambda (elt)
  235.                    (and (listp elt)
  236.                     (vectorp (setq arg-vector (nth 2 elt)))
  237.                     arg-vector)))
  238.                    body))))
  239.       ;; assume V19 byte compiler   (eq (compiled-function-p body) t)
  240.       (setq arg (aref body 2)
  241.         arg-vector (if (vectorp arg) arg))
  242.       )
  243.     (if arg-vector
  244.     ;; Code is byte-compiled.
  245.     (let ((i (1- (length arg-vector))))
  246.       (setq arg nil)
  247.       (while (and (not arg) (>= i 0))
  248.         (if (eq (setq arg (aref arg-vector i)) sym-to-replace)
  249.         (aset arg-vector i replace-with-sym)
  250.           (setq arg nil i (1- i)))))
  251.       ;; Code is not byte-compiled.
  252.       ;; Only replaces occurrence of symbol as an element of a list.
  253.       (hypb:map-sublists
  254.     (function
  255.       (lambda (atom list) (if (eq atom sym-to-replace)
  256.                   (let ((again t))
  257.                     (while (and again list)
  258.                       (if (eq (car list) atom)
  259.                       (progn (setcar list replace-with-sym)
  260.                          (setq again nil))
  261.                     (setq list (cdr list))))))))
  262.     body)
  263.       )
  264.     body))
  265.  
  266. (defun hypb:help-buf-name (&optional prefix)
  267.   "Returns a Hyperbole help buffer name for current buffer.
  268. With optional PREFIX string, uses it rather than buffer name."
  269.   (let ((bn (or prefix (buffer-name))))
  270.     (if (string-match " Hypb " bn)
  271.     (buffer-name (generate-new-buffer bn))
  272.       (concat "*" bn hypb:help-buf-suffix))))
  273.  
  274. (defun hypb:indirect-function (obj)
  275.   "Return the function at the end of OBJ's function chain.
  276. Resolves autoloadable function symbols properly."
  277.   (let ((func
  278.      (if (fboundp 'indirect-function)
  279.          (indirect-function obj)
  280.        (while (symbolp obj)
  281.          (setq obj (symbol-function obj)))
  282.        obj)))
  283.     ;; Handle functions with autoload bodies.
  284.     (if (and (symbolp obj) (listp func) (eq (car func) 'autoload))
  285.     (let ((load-file (car (cdr func))))
  286.       (load load-file)
  287.       ;; Prevent infinite recursion
  288.       (if (equal func (symbol-function obj))
  289.           (error "(hypb:indirect-function): Autoload of '%s' failed" obj)
  290.         (hypb:indirect-function obj)))
  291.       func)))
  292.  
  293. (if (or hyperb:lemacs-p hyperb:emacs19-p)
  294.     (fset 'hypb:mark 'mark)
  295.   (defun hypb:mark (inactive-p)
  296.     "Return this buffer's mark value as integer, or nil if no mark.
  297. INACTIVE-P non-nil means return value of mark even if region is not active
  298. under Emacs version 19.
  299. If you are using this in an editing command, you are most likely making
  300. a mistake; see the documentation of `set-mark'."
  301.     (mark))
  302.   )
  303. (if hyperb:lemacs-p
  304.     (fset 'hypb:mark-marker 'mark-marker)
  305.   (defun hypb:mark-marker (inactive-p)
  306.     "Return this buffer's mark as a marker object, or nil if no mark.
  307. INACTIVE-P is unused, it is for compatibility with Lucid Emacs'
  308. version of mark-marker."
  309.     (mark-marker))
  310.   )
  311.  
  312. (defun hypb:map-sublists (func list)
  313.   "Applies FUNC to every atom found at any level of LIST.
  314. FUNC must take two arguments, an atom and a list in which the atom is found.
  315. Returns values from applications of FUNC as a list with the same
  316. structure as LIST.  FUNC is therefore normally used just for its side-effects."
  317.   (mapcar (function
  318.         (lambda (elt) (if (atom elt)
  319.                   (funcall func elt list)
  320.                 (hypb:map-sublists func elt)))
  321.         list)))
  322.  
  323. (defun hypb:map-vector (func object)
  324.   "Returns list of results of application of FUNC to each element of OBJECT.
  325. OBJECT should be a vector or byte-code object."
  326.   (if (not (or (vectorp object) (hypb:v19-byte-code-p object)))
  327.       (error "(hypb:map-vector): Second argument must be a vector or byte-code object."))
  328.   (let ((end (length object))
  329.     (i 0)
  330.     (result))
  331.     (while (< i end)
  332.       (setq result (cons (funcall func (aref object i)) result)
  333.         i (1+ i)))
  334.     (nreverse result)))
  335.  
  336. (defun hypb:mouse-help-file ()
  337.   "Return the full path to the Hyperbole mouse key help file."
  338.   (let* ((hypb-man (expand-file-name "man/" hyperb:dir))
  339.      (help-file (expand-file-name "hypb-mouse.txt" hypb-man)))
  340.     (if (or (file-exists-p help-file)
  341.         (file-exists-p
  342.          (setq help-file (expand-file-name
  343.                   "hypb-mouse.txt" data-directory))))
  344.     help-file
  345.       (error "(hypb:mouse-help-file): Non-existent file: \"%s\"" help-file))))
  346.  
  347. (if (or hyperb:lemacs-p hyperb:emacs19-p)
  348.     (fset 'hypb:push-mark 'push-mark)
  349.   (defun hypb:push-mark (&optional location nomsg activate-region)
  350.     "Set mark at LOCATION (point, by default) and push old mark on mark ring.
  351. If the last global mark pushed was not in the current buffer,
  352. also push LOCATION on the global mark ring.
  353. Display `Mark set' unless the optional second arg NOMSG is non-nil.
  354. Optional third arg ACTIVATE-REGION is ignored.
  355.  
  356. Novice Emacs Lisp programmers often try to use the mark for the wrong
  357. purposes.  See the documentation of `set-mark' for more information."
  358.     (push-mark location nomsg))
  359.   )
  360.  
  361. (defun hypb:replace-match-string (regexp str newtext &optional literal)
  362.   "Replaces all matches for REGEXP in STR with NEWTEXT string.
  363. Optional LITERAL non-nil means do a literal replacement.
  364. Otherwise treat \\ in NEWTEXT string as special:
  365.   \\& means substitute original matched text,
  366.   \\N means substitute match for \(...\) number N,
  367.   \\\\ means insert one \\.
  368. NEWTEXT may instead be a function of one argument, the string to replace in,
  369. that returns a replacement string."
  370.   (if (not (stringp str))
  371.       (error "(hypb:replace-match-string): 2nd arg must be a string: %s" str))
  372.   (if (or (stringp newtext) (hypb:functionp newtext))
  373.       nil
  374.     (error "(hypb:replace-match-string): 3rd arg must be a string or function: %s"
  375.        newtext))
  376.   (let ((rtn-str "")
  377.     (start 0)
  378.     (special)
  379.     match prev-start)
  380.     (while (setq match (string-match regexp str start))
  381.       (setq prev-start start
  382.         start (match-end 0)
  383.         rtn-str
  384.         (concat
  385.           rtn-str
  386.           (substring str prev-start match)
  387.           (cond ((hypb:functionp newtext) (funcall newtext str))
  388.             (literal newtext)
  389.             (t (mapconcat
  390.              (function
  391.                (lambda (c)
  392.                  (if special
  393.                  (progn
  394.                    (setq special nil)
  395.                    (cond ((eq c ?\\) "\\")
  396.                      ((eq c ?&)
  397.                       (substring str
  398.                              (match-beginning 0)
  399.                              (match-end 0)))
  400.                      ((and (>= c ?0) (<= c ?9))
  401.                       (if (> c (+ ?0 (length
  402.                                (match-data))))
  403.                           ;; Invalid match num
  404.                           (error "(hypb:replace-match-string) Invalid match num: %c" c)
  405.                         (setq c (- c ?0))
  406.                         (substring str
  407.                                (match-beginning c)
  408.                                (match-end c))))
  409.                      (t (char-to-string c))))
  410.                    (if (eq c ?\\) (progn (setq special t) nil)
  411.                  (char-to-string c)))))
  412.              newtext ""))))))
  413.     (concat rtn-str (substring str start))))
  414.  
  415. (defun hypb:supercite-p ()
  416.   "Returns non-nil iff the Emacs add-on supercite package is in use."
  417.   (let (hook-val)
  418.     (memq t (mapcar
  419.          (function
  420.           (lambda (hook-var)
  421.         (and (boundp hook-var)
  422.              (progn (setq hook-val (symbol-value hook-var))
  423.                 (cond ((listp hook-val)
  424.                    (memq 'sc-cite-original hook-val))
  425.                   (t (eq hook-val 'sc-cite-original)))))))
  426.          '(mail-citation-hook mail-yank-hooks)))))
  427.  
  428. ;;; Next function is copied from a copylefted function:
  429. ;;; Copyright (C) 1987, 1988 Kyle E. Jones
  430. (if (or hyperb:lemacs-p hyperb:emacs19-p)
  431.     (defun hypb:window-list-all-frames (&optional mini)
  432.       "Returns a list of Lisp window objects for all Emacs windows in all frames.
  433. Optional first arg MINI t means include the minibuffer window
  434. in the list, even if it is not active.  If MINI is neither t
  435. nor nil it means to not count the minibuffer window even if it is active."
  436.       (let* ((first-window (next-window
  437.                 (previous-window (selected-window) nil t t)
  438.                 mini t t))
  439.          (windows (cons first-window nil))
  440.          (current-cons windows)
  441.          (w (next-window first-window mini t t)))
  442.     (while (not (eq w first-window))
  443.       (setq current-cons (setcdr current-cons (cons w nil)))
  444.       (setq w (next-window w mini t t)))
  445.     windows)))
  446.  
  447. ;;; Next function is copied from a copylefted function:
  448. ;;; Copyright (C) 1987, 1988 Kyle E. Jones
  449. (defun hypb:window-list (&optional mini)
  450.   "Returns a list of Lisp window objects for all Emacs windows in selected frame.
  451. Optional first arg MINI t means include the minibuffer window
  452. in the list, even if it is not active.  If MINI is neither t
  453. nor nil it means to not count the minibuffer window even if it is active."
  454.   (let* ((first-window (next-window
  455.             (previous-window (selected-window)) mini))
  456.      (windows (cons first-window nil))
  457.      (current-cons windows)
  458.      (w (next-window first-window mini)))
  459.     (while (not (eq w first-window))
  460.       (setq current-cons (setcdr current-cons (cons w nil)))
  461.       (setq w (next-window w mini)))
  462.     windows))
  463.  
  464. (defun hypb:v19-byte-code-p (obj)
  465.   "Return non-nil iff OBJ is an Emacs V19 byte compiled object."
  466.   (or (and (fboundp 'compiled-function-p) (compiled-function-p obj))
  467.       (and (fboundp 'byte-code-function-p) (byte-code-function-p obj))))
  468.  
  469. ;;; ************************************************************************
  470. ;;; Private functions
  471. ;;; ************************************************************************
  472.  
  473. (defun hypb:oct-to-int (oct-num)
  474.   "Returns octal integer OCTAL-NUM converted to a decimal integer."
  475.   (let ((oct-str (int-to-string oct-num))
  476.     (dec-num 0))
  477.     (and (string-match "[^0-7]" oct-str)
  478.      (error (format "(hypb:oct-to-int): Bad octal number: %s" oct-str)))
  479.     (mapconcat (function
  480.         (lambda (o)
  481.           (setq dec-num (+ (* dec-num 8)
  482.                    (if (and (>= o ?0) (<= o ?7))
  483.                        (- o ?0))))))
  484.            oct-str "")
  485.     dec-num))
  486.  
  487. ;;; ************************************************************************
  488. ;;; Private variables
  489. ;;; ************************************************************************
  490.  
  491. (provide 'hypb)
  492.